#include "../include/TCPConnection.hpp"
#include "../include/EventLoop.hpp"

#include <string.h>
#include <iostream>
#include <sstream>

using std::cout;
using std::endl;
using std::ostringstream;

namespace cdm{

TCPConnection::TCPConnection(int fd,EventLoop *loop)
    :_socket(fd),
    _localAddr(getLocalAddress()),
    _peerAddr(getPeerAddress()),
    _loop(loop),
    _sockIO(_socket.fd()),
    _isShutdownWrite(false)
{

}

TCPConnection::~TCPConnection(){
}

string TCPConnection::recive(){
    char buff[65535] = {};
    int ret = _sockIO.readLine(buff,sizeof(buff));
    return string(buff,ret);
}

int TCPConnection::readPacket(Packet &packet){
    return _sockIO.readPacket(packet);
}

void TCPConnection::send(const string &msg){
    if(msg.size()>0){
        _sockIO.sendN(msg.c_str(),msg.size());
    }
}

void TCPConnection::sendInLoop(const string &msg){
    if(_loop){
        _loop->runInLoop(std::bind(&TCPConnection::send,this,msg));
    }
}

void TCPConnection::sendInLoop(const TLV &data){
    int len = 8 + data.length;
    string msg;
    msg.assign((const char*)&data,len);
    sendInLoop(msg);
}

void TCPConnection::shutdown(){
    if(!_isShutdownWrite){
        _isShutdownWrite = true;
        _socket.shutdownWrite();
    }
}

bool TCPConnection::isClose(){
    char buff[20] = {0};
    return _sockIO.recvPeek(buff,sizeof(buff)) == 0;
}

string TCPConnection::toString(){
    ostringstream oss;
    oss<<"TCP "<<_localAddr.ip()<<":"<<_localAddr.port()
        <<"->"<<_peerAddr.ip()<<":"<<_peerAddr.port();
    return oss.str();
}

void TCPConnection::handleConnection(){
    if(_onConnection){
        _onConnection(shared_from_this());
    }
}

void TCPConnection::handleMessage(){
    if(_onMessage){
        _onMessage(shared_from_this());
    }
}

void TCPConnection::handleClose(){
    if(_onClose){
        _onClose(shared_from_this());
    }
}

InetAddress TCPConnection::getLocalAddress(){
    struct sockaddr_in addr;
    memset(&addr,0,sizeof(addr));
    socklen_t len = sizeof(addr);
    int ret = getsockname(_socket.fd(),(struct sockaddr*)&addr,&len);
    if(ret < 0){
        perror("getsockname");
    }
    return InetAddress(addr);
}

InetAddress TCPConnection::getPeerAddress(){
    struct sockaddr_in addr;
    memset(&addr,0,sizeof(addr));
    socklen_t len = sizeof(addr);
    int ret = getpeername(_socket.fd(),(struct sockaddr*)&addr,&len);
    if(ret < 0){
        perror("getpeername");
    }
    return InetAddress(addr);
}

}//end of namespace

